package com.xyazm.order.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.xyazm.common.constants.RocketDelayedLevelConstant;
import com.xyazm.common.constants.RocketMqConstant;
import com.xyazm.common.enums.OrderStatusChangeEnum;
import com.xyazm.common.enums.OrderStatusEnum;
import com.xyazm.common.enums.OrderTypeEnum;
import com.xyazm.common.enums.RocketMqTopicEnum;
import com.xyazm.common.logger.LoggerFormat;
import com.xyazm.common.utils.DateFormatUtil;
import com.xyazm.coupon.domain.param.ReleaseUserCouponParam;
import com.xyazm.customer.domain.param.ReceiveAfterSaleAuditParam;
import com.xyazm.order.dao.OrderDeliveryDetailDAO;
import com.xyazm.order.dao.OrderInfoDAO;
import com.xyazm.order.domain.dto.CancelOrderAssembleDTO;
import com.xyazm.order.domain.dto.ManualAfterSaleDTO;
import com.xyazm.order.domain.dto.OrderInfoDTO;
import com.xyazm.order.domain.entity.OrderDeliveryDetailDO;
import com.xyazm.order.domain.mq.ActualRefundDTO;
import com.xyazm.order.domain.mq.OrderPaymentDelayDTO;
import com.xyazm.order.domain.mq.SendOrderStatusChangeEventDTO;
import com.xyazm.order.enums.AfterSaleStateChangeEnum;
import com.xyazm.order.enums.BusinessIdentifierEnum;
import com.xyazm.order.mapstruct.OrderApiMapstruct;
import com.xyazm.order.mq.producer.DefaultProducer;
import com.xyazm.order.service.IMqMessageService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;


@Slf4j
@Service
public class MqMessageServiceImpl implements IMqMessageService {

    @Autowired
    private DefaultProducer defaultProducer;

    @Autowired
    private OrderInfoDAO orderInfoDAO;

    @Autowired
    private OrderDeliveryDetailDAO deliveryDetailDAO;

    @Override
    // @ConsistencyTask(id = "sendOrderPayTimeoutDelayMessage", alertActionBeanName = "tendConsistencyAlerter")
    public void sendOrderPayTimeoutDelayMessage(OrderPaymentDelayDTO orderPaymentDelayDTO) {
        String orderId = orderPaymentDelayDTO.getOrderId();
        Map<String, String> map = new HashMap<>(16);
        map.put("orderId", orderId);
        defaultProducer.sendMessage(
                RocketMqTopicEnum.PAY_ORDER_TIMEOUT_DELAY.getTopic(),
                JSONObject.toJSONString(map),
                RocketDelayedLevelConstant.DELAYED_30m,
                "支付订单超时延迟消息",
                AfterSaleStateChangeEnum.CANCEL_ORDER.getTags(),
                orderId);
    }

    @Override
    // @ConsistencyTask(id = "sendStandardOrderStatusChangeMessage", alertActionBeanName = "tendConsistencyAlerter")
    public void sendStandardOrderStatusChangeMessage(SendOrderStatusChangeEventDTO sendOrderStatusChangeEventDTO) {
        String orderId = sendOrderStatusChangeEventDTO.getOrderId();
        OrderStatusChangeEnum orderStatusChangeEnum = sendOrderStatusChangeEventDTO.getOrderStatusChangeEnum();

        // 1、从数据库查询订单
        OrderInfoDTO orderInfoDTO = OrderApiMapstruct.INSTANCE.convertOrderInfoDTO(orderInfoDAO.getByOrderId(orderId));
        // 2、构造标准订单变更消息
        SendOrderStatusChangeEventDTO sendOrderStatusChangeEvent = buildSendOrderStatusChangeEvent(orderStatusChangeEnum, orderInfoDTO);
        // 3、发送标准变更消息
        sendMessage(JSONObject.toJSONString(sendOrderStatusChangeEvent), sendOrderStatusChangeEvent.getOrderId(), orderStatusChangeEnum.getTags());
    }

    @Override
    // @ConsistencyTask(id = "sendReleaseAssetsMessage", alertActionBeanName = "tendConsistencyAlerter")
    public void sendReleaseAssetsMessage(CancelOrderAssembleDTO cancelOrderAssembleDTO) {
        defaultProducer.sendMessage(
                RocketMqConstant.RELEASE_ASSETS_TOPIC,
                JSONObject.toJSONString(cancelOrderAssembleDTO),
                -1,
                "取消订单释放资产权益消息",
                AfterSaleStateChangeEnum.CANCEL_ORDER.getTags(),
                cancelOrderAssembleDTO.getOrderId()
        );
    }

    @Override
    // @ConsistencyTask(id = "sendCancelOrderRefundMessage", alertActionBeanName = "tendConsistencyAlerter")
    public void sendActualRefundMessage(ActualRefundDTO actualRefundDTO) {
        defaultProducer.sendMessage(
                RocketMqConstant.ACTUAL_REFUND_TOPIC,
                JSONObject.toJSONString(actualRefundDTO),
                -1,
                "取消订单发送实际退款消息",
                AfterSaleStateChangeEnum.CANCEL_ORDER.getTags(),
                actualRefundDTO.getOrderId()
        );
    }


    @Override
    // @ConsistencyTask(id = "sendAfterSaleRefundMessage", alertActionBeanName = "tendConsistencyAlerter")
    public void sendAfterSaleRefundMessage(ManualAfterSaleDTO manualAfterSaleDTO) {
        // 保存售后申请数据
        ReceiveAfterSaleAuditParam receiveAfterSaleAuditParam =
                OrderApiMapstruct.INSTANCE.convertReceiveAfterSaleAuditParam(manualAfterSaleDTO);
        defaultProducer.sendMessage(
                RocketMqConstant.AFTER_SALE_CUSTOMER_AUDIT_TOPIC,
                JSONObject.toJSONString(receiveAfterSaleAuditParam),
                -1,
                "售后发送实际退款消息",
                AfterSaleStateChangeEnum.INITIATE_AFTER_SALE.getTags(),
                manualAfterSaleDTO.getOrderId()
        );

    }



    @Override
    // @ConsistencyTask(id = "sendAfterSaleReleaseCouponMessage", alertActionBeanName = "tendConsistencyAlerter")
    public void sendAfterSaleReleaseCouponMessage(ReleaseUserCouponParam releaseUserCouponParam) {
        defaultProducer.sendMessage(
                RocketMqConstant.AFTER_SALE_RELEASE_COUPON_TOPIC,
                JSONObject.toJSONString(releaseUserCouponParam),
                -1,
                "售后释放优惠券消息",
                AfterSaleStateChangeEnum.REFUNDING.getTags(),
                releaseUserCouponParam.getOrderId()
        );
    }


    private SendOrderStatusChangeEventDTO buildSendOrderStatusChangeEvent(OrderStatusChangeEnum event, OrderInfoDTO order) {
        // 构造正向订单标准变更消息
        SendOrderStatusChangeEventDTO stdChangeEvent = SendOrderStatusChangeEventDTO.builder()
                .orderId(order.getOrderId())
                .businessIdentifier(BusinessIdentifierEnum.getByCode(order.getBusinessIdentifier()))
                .orderType(OrderTypeEnum.getByCode(order.getOrderType()))
                .businessOrderId(order.getBusinessOrderId())
                .parentOrderId(order.getParentOrderId())
                .payAmount(order.getPayAmount())
                .orderStatusChangeEnum(event)
                .payTime(DateFormatUtil.formatDatetime(order.getPayTime()))
                .payType(order.getPayType())
                .sellerId(order.getSellerId())
                .totalAmount(order.getTotalAmount())
                .userId(order.getUserId())
                .build();

        // 如果是出库后的状态
        if (OrderStatusEnum.afterOutStockStatus().contains(order.getOrderStatus())) {
            OrderDeliveryDetailDO deliveryDetail = deliveryDetailDAO.getByOrderId(order.getOrderId());
            stdChangeEvent.setOutStockTime(DateFormatUtil.formatDatetime(deliveryDetail.getOutStockTime()));
            stdChangeEvent.setSignedTime(DateFormatUtil.formatDatetime(deliveryDetail.getSignedTime()));
        }
        return stdChangeEvent;
    }



    private void sendMessage(String body, String orderId, String tags) {
        log.info(LoggerFormat.build()
                .remark("OrderStateAction->sendMessage")
                .data("body", body)
                .data("orderId", orderId)
                .data("tags", tags)
                .finish());
        if (StringUtils.isBlank(body)) {
            return;
        }
        defaultProducer.sendMessage(
                RocketMqTopicEnum.ORDER_STATE_CHANGE_EVENT.getTopic(),body,
                -1, "订单变更标准消息",
                tags, orderId, (mqs, message, arg) -> {
                    //根据订单id选择发送queue
                    String orderId1 = (String) arg;
                    long index = hash(orderId1) % mqs.size(); // 通过一个订单id对应的消息都发送到mq queue里去
                    return mqs.get((int) index);
                }, orderId);
    }

    /**
     * hash
     *
     * @param orderId 订单id
     * @return hash后的值
     */
    private int hash(String orderId) {
        //解决取模可能为负数的情况
        return orderId.hashCode() & Integer.MAX_VALUE;
    }
}
